﻿using DDotNet.Data.BusinessObjects;
using DDotNet.Data.BusinessObjects.Validation;
using DDotNet.Data.CodeGen.Model.Collection;
using DDotNet.Data.CodeGen.Model.Struct;

namespace DDotNet.Data.CodeGen.Model.Entity.Abstract
{
    /// <summary>
    /// Classe Abstrata de Projeto
    /// </summary>
    public abstract class AbstractProject : BusinessBase<Project>
    {
        #region Constructor

        public AbstractProject()
        {
            this._Fields.associatedUsers = new UserCollection();
        }

        #endregion
        
        #region Fields Declaration

        private ProjectStruct _Fields = new ProjectStruct();

        #endregion

        #region Properties

        /// <summary>
        /// Contém o ID do Projeto
        /// </summary>
        public int ID
        {
            get
            {
                CanReadProperty("ID", true);
                return this._Fields.id;
            }
        }

        /// <summary>
        /// Contém o Nome do Projeto
        /// </summary>
        public string Name
        {
            get
            {
                CanReadProperty("Name", true);
                return this._Fields.name;
            }
            set
            {
                CanWriteProperty("Name", true);
                if (value == null)
                {
                    value = string.Empty;
                }
                if (this._Fields.name != value)
                {
                    this._Fields.name = value;
                    PropertyHasChanged("Name");
                }
            }
        }

        /// <summary>
        /// Contém a Data de Início do Projeto
        /// </summary>
        public SmartDate StartDate
        {
            get
            {
                CanReadProperty("StartDate", true);
                return this._Fields.startDate;
            }
            set
            {
                CanWriteProperty("StartDate", true);
                if (this._Fields.startDate != value)
                {
                    this._Fields.startDate = value;
                    PropertyHasChanged("StartDate");
                }
            }
        }

        /// <summary>
        /// Contém os Usuário Associados ao Projeto
        /// </summary>
        public UserCollection AssociatedUsers
        {
            get
            {
                CanReadProperty("UserCollection", true);
                return this._Fields.associatedUsers;
            }
        }

        #endregion

        #region BusinessBase Overrided Members

        /// <summary>
        /// Returns <see langword="true" /> if this object's data has been changed.
        /// </summary>
        /// <remarks>
        /// <para>
        /// When an object's data is changed, CSLA .NET makes note of that change
        /// and considers the object to be 'dirty' or changed. This value is used to
        /// optimize data updates, since an unchanged object does not need to be
        /// updated into the database. All new objects are considered dirty. All objects
        /// marked for deletion are considered dirty.
        /// </para><para>
        /// Once an object's data has been saved to the database (inserted or updated)
        /// the dirty flag is cleared and the object is considered unchanged. Objects
        /// newly loaded from the database are also considered unchanged.
        /// </para>
        /// </remarks>
        /// <returns>A value indicating if this object's data has been changed.</returns>
        public override bool IsDirty
        {
            get { return base.IsDirty || this._Fields.associatedUsers.IsDirty; }
        }

        /// <summary>
        /// Returns <see langword="true" /> if the object is currently valid, <see langword="false" /> if the
        /// object has broken rules or is otherwise invalid.
        /// </summary>
        /// <remarks>
        /// <para>
        /// By default this property relies on the underling ValidationRules
        /// object to track whether any business rules are currently broken for this object.
        /// </para><para>
        /// You can override this property to provide more sophisticated
        /// implementations of the behavior. For instance, you should always override
        /// this method if your object has child objects, since the validity of this object
        /// is affected by the validity of all child objects.
        /// </para>
        /// </remarks>
        /// <returns>A value indicating if the object is currently valid.</returns>
        public override bool IsValid
        {
            get { return base.IsValid && this._Fields.associatedUsers.IsValid; }
        }

        #endregion

        #region Validation Methods

        /// <summary>
        /// Método para Indicar se a Entidade pode ser Excluída
        /// </summary>
        /// <returns></returns>
        public override void CanDeleteObject()
        {
            base.CanDeleteObject();
        }

        /// <summary>
        /// Método para Indicar se a Entidade por ser Criada/Adicionada
        /// </summary>
        /// <returns></returns>
        public override void CanAddObject()
        {
            base.CanAddObject();
        }

        /// <summary>
        /// Método para Indicar se a Entidade por ser Alterada
        /// </summary>
        /// <returns></returns>
        public override void CanEditObject()
        {
            base.CanEditObject();
        }

        #endregion

        /// <summary>
        /// Saves the object to the database.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Calling this method starts the save operation, causing the object
        /// to be inserted, updated or deleted within the database based on the
        /// object's current state.
        /// </para><para>
        /// If <see cref="BusinessBase.IsDeleted" /> is <see langword="true"/>
        /// the object will be deleted. Otherwise, if <see cref="BusinessBase.IsNew" /> 
        /// is <see langword="true"/> the object will be inserted. 
        /// Otherwise the object's data will be updated in the database.
        /// </para><para>
        /// All this is contingent on <see cref="BusinessBase.IsDirty" />. If
        /// this value is <see langword="false"/>, no data operation occurs. 
        /// It is also contingent on <see cref="BusinessBase.IsValid" />. 
        /// If this value is <see langword="false"/> an
        /// exception will be thrown to indicate that the UI attempted to save an
        /// invalid object.
        /// </para><para>
        /// It is important to note that this method returns a new version of the
        /// business object that contains any data updated during the save operation.
        /// You MUST update all object references to use this new version of the
        /// business object in order to have access to the correct object data.
        /// </para><para>
        /// You can override this method to add your own custom behaviors to the save
        /// operation. For instance, you may add some security checks to make sure
        /// the user can save the object. If all security checks pass, you would then
        /// invoke the base Save method via <c>base.Save()</c>.
        /// </para>
        /// </remarks>
        /// <returns>A new object containing the saved values.</returns>
        public override Project Save()
        {
            try
            {
                if (IsDeleted) // Deleted Entity
                {
                    CanDeleteObject();
                }
                else if (IsNew) // New Entity
                {
                    CanAddObject();
                }
                else // Old Entity
                {
                    CanEditObject();
                }
            }
            catch (ValidationException e)
            {
                throw e;
            }

            return base.Save();
        }
        
    }
}